Description ================================= DSGE (Dynamic Stochastic General Equilibrium) models are a type of macroeconomic model that are widely used in modern macroeconomics. Some of the strengths of these models include: .. #. **Realism**: DSGE models incorporate realistic assumptions about the behavior of agents, such as consumers and firms, and are therefore able to generate predictions that are more in line with observed data. .. #. **Identification**: DSGE models are able to identify the structural parameters of the economy, such as the elasticity of intertemporal substitution, which can be used to interpret the model and make policy recommendations. #. **Microfoundations**: DSGE models are based on microeconomic principles and are therefore able to provide a consistent and coherent framework for analyzing macroeconomic phenomena. #. **Flexibility**: DSGE models can be used to analyze a wide range of macroeconomic phenomena, including business cycles, inflation, and growth. #. **Quantitative**: DSGE models are able to generate quantitative predictions about the economy, and forecasts that compare well with other classes of models such as Bayesian VARs. #. **Policy Analysis**: DSGE models can be used to analyze the effects of different policy changes, such as changes in interest rates, government spending or exchange rate regimes. #. **International aspects**: Some DSGE models are able to incorporate international aspects such as trade, currency and capital flows. RISE extends the constant-parameter DSGE model to allow for regime switching. The regime-switching DSGE model is given by: .. math:: E_{t}\sum_{r_{t+1}=1}^{h}p_{r_{t},r_{t+1}}\left( \mathcal{I}_{t}\right) f_{r_{t}}\left( x_{t+1}\left( r_{t+1}\right) ,x_{t}\left( r_{t}\right) ,x_{t-1},\theta_{r_{t}},\theta_{r_{t+1}},\varepsilon_{t}\right) =0 - :math:`p_{r_{t},r_{t+1}}\left( I_{t}\right)` : probability of going from state :math:`r_{t}` in the current period to state :math:`r_{t+1}` in the next one - :math:`f_{r_{t}}`: (potentially) nonlinear function of its arguments - :math:`x_{t}\left( r_{t}\right)` : vector of all endogenous variables in the current regime :math:`r_{t}` - :math:`\theta _{r_{t}}`: parameters in the current regime - :math:`\varepsilon _{t}\sim N\left( 0,I\right)` : vector of stochastic shocks An example =============== See the previous chapter. The model(rise/dsge) file language ==================================== Conventions ------------- Comments and block comments ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RISE supports single line comments %, or //:: % this is a comment // this is also a comment RISE supports block comments of the Matlab style %, or //:: %{ This is a block comment That RISE will ignore %} Time and steady state ~~~~~~~~~~~~~~~~~~~~~~~~~~~ Our preferred way to denote time uses curly braces. But RISE would also accept parentheses although in that case it becomes difficult to know whether we are referring to a variable or a function. That said, - For contemporaneous variables we have : X = X{0} = X{t+0} = X{t} = X(0) = X(t+0) = X(t) - For lagged variables we have : X{-1} = X{t-1} = X(-1) = X(t-1) - For lead variables we have : X{1} = X{+1} = X{t+1} = X(1) = X(+1) = X(t+1) - For the steady state we have : X{stst} = steady_state(X) = X(stst) In brief, RISE is flexible. Use the notation that you prefer! Auxiliary variables ~~~~~~~~~~~~~~~~~~~~~ RISE automatically creates auxiliary variables so that the maximum lag and the maximum lead for any model is always 1. The user should not worry about these variables. RISE also handles expectations that appear inside an equation. E.g. .. math:: Y_{t}=1/E_t\left(X_{t+1}\right) In order to avoid RISE computing .. math:: Y_{t}=E_t\left(1/X_{t+1}\right) It is the responsibility of the user to create the appropriate auxiliary variable, say, :math:`A_{t}=E_t\left(X_{t+1}\right)` and then rewrite the equation as .. math:: Y{t}=1/A_{t} Or to write the equation differently .. math:: E_t\left(Y_{t} X_{t+1}\right)=1 Or explicitly use the expectations operator by writing the equation as .. code:: text Y{t} = 1/@E[t](X{t+1}) .. note:: RISE automatically creates auxiliary variables to deal with - leads and lags greater than 1 and - switching parameters with a different dating than the current period - see the @E section for the expectation operator Functions ~~~~~~~~~~~~~~~~~ Known functions """"""""""""""""" RISE supports four basic arithmetical operations (+, -, \*, /) as well as powers (^). RISE relies on Matlab for these operations and so one has to be careful with the power and rdivide (/) operators : - :math:`{a^b}^c = (a^b)^c` for a^b^c - :math:`a/b^c = a/(b^c)` for a/b^c Naturally, the precedence of arithmetical operators can be changed using parentheses. The list of functions that RISE knows how to differentiate includes : *abs, acos, acosh, and, asin, asinh, atan, atanh, betacdf, betainv*, *betapdf, char, cos, cosh, cot, eq, erf, exp, ge, get, gt*, *kron, le, log, log10, lt, max, min, minus, mpower, mrdivide, mtimes, ne, normcdf, norminv*, *normpdf, or, plus, power, rdivide, sign, sin, sinh, sqrt, tan, tanh, times, uminus, uplus*. External functions """"""""""""""""""" Sometimes, the user may have a function that is unknown to RISE. In that case, the user should write the function such that RISE can evaluate it as well as its derivatives. The function should be written so that it is possible to call it in two different ways:: x=f(a1,a2,...,an) x=f(a1,a2,...,an,'diff',der) where : - x is the output of the function - a1, a2, ..., an : are the main inputs of the function - 'diff' is an input that signals that triggers the computation of derivatives - der is a scalar of or a 1 x k vector specifying the derivatives requested. The number of elements, k, in der is the order of differentiation. The numbers in the vector are the location of the elements to differentiate. E.g: - x=f(a1,a2,...,an,'diff',1) : first-order derivative wrt first argument - x=f(a1,a2,...,an,'diff',[1,2]) : second-order derivative wrt arguments 1 and then 2 - x=f(a1,a2,...,an,'diff',[1,2,3]) : third-order derivative wrt arguments 1, 2, and 3 - x=f(a1,a2,...,an,'diff',[i,j,k,l,m]) : fifth-order derivative wrt arguments i, k, k, l, and m It is expected that - f(a,'diff',[i,j])=f(a,'diff',[j,i]) - f(a,'diff',[i,j,k]) = f(a,'diff',[i,k,j]) = f(a,'diff',[j,i,k]) = f(a,'diff',[j,k,i]) = f(a,'diff',[k,i,j]) = f(a,'diff',[k,j,i]) - etc Discountinous functions ~~~~~~~~~~~~~~~~~~~~~~~~~~ On local approximations """""""""""""""""""""""""" RISE approximates discontinuous functions in the same way it does with continuous functions. As a result, inequality constraints such as max or min will not hold when solving a model using perturbation. One way to assuage the problem is to replace discontinuous functions with smooth approximations and solve the model using higher-order perturbations. Even so, the inequalities will not necessarily be satisfied. Another way to deal with the problem is to use algorithms designed for occasionally-binding constraints. In that respect, RISE implements four classes of algorithms : #. perfect foresight (and extended path) #. piecewise linear approximations #. anticipated shocks #. regime switching .. danger:: There is a widespread belief that projection methods can successfully deal with problems of with discontinuous functions. This is untrue ! Smooth approximations """"""""""""""""""""""""""""" RISE implements smooth approximations of abs, min and max functions. They can be accessed respectively as : - sabs - smin - smax Shock distributions ~~~~~~~~~~~~~~~~~~~~~~ In RISE, all shocks have zero mean and standard deviation 1. By default, they are normally distributed. Skewed shocks or more generally shocks having non-normal distributions are easily accommodated. However, even they should have mean zero and variance 1. Therefore, we will not have variance-covariance matrices of shocks. The way to handle correlated shocks in RISE is to create auxiliary endogenous variables that are combinations of uncorrelated shocks. First and second-order moments of shocks """""""""""""""""""""""""""""""""""""""""""" All shocks have mean 0 and standard deviation 1 Higher-order moments of shocks """""""""""""""""""""""""""""""""" Skewed shocks are declared in a structure. Each element of the structure represents a particular shock and is given in a 1-by-2 cell array of functions. - The first element of the cell array computes moments and takes two inputs : the model object and the moment order - The second element of the cell array computes draws from the distribution. It should take as inputs the same inputs as matlab's rand or randn functions. Eventually, the structure is passed to the model object through the option **solve_user_defined_shocks** e.g. m=set(m,'solve_user_defined_shocks',myshocks) Here is an example on how to write a function of skewed shocks .. code-block:: matlab function myshocks=online_skewed_shocks(dof) if nargin==0 dof=1; end myshocks=struct(); momfunE=@(obj,order)moments.tailored_chisquare(order,dof); tmpfun=@(varargin)if_then_else(length(varargin)>1,[varargin{:}],[1,varargin{1}]); drawfunE=@(varargin)reshape(... (sum(randn(dof,prod([varargin{:}])).^2,1)-dof)/sqrt(2*dof),... tmpfun(varargin{:})); myshocks.E={momfunE,drawfunE}; norm_moments=[0,1,0,3,0,15,0,105,0,945]; momfunOMEGA=@(obj,order)norm_moments(1:order); drawfunOMEGA=@(varargin)reshape(randn(1,prod([varargin{:}])),tmpfun(varargin{:})); myshocks.OMEGA={momfunOMEGA,drawfunOMEGA}; end Ways to declare a model ------------------------------- A model in RISE can be declared in three main ways: using a model file, as an inline snippet embedded in a script, or as a cell array directly in MATLAB. Declaring a model in a file ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A model can be declared in a text file with extensions ".rs", ".rz", or ".dsge". These files contain the full specification of the model, including the endogenous and exogenous variables, parameters, and model equations. By placing double comments "%%" at the top of the file, followed by a comment, RISE will use that comment as a description of the model. Declaring a Model as an Inline Snippet ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ A RISE model can also be declared directly within a MATLAB script as an **inline snippet**. This is a piece of model code embedded directly in the script using a specific format for defining endogenous variables, parameters, and equations. The snippet is extracted and processed by RISE using a function call. Example of an inline snippet within a MATLAB script:: m = rise.from_code_snippet('myModel'); %{ \begin{snippet}{myModel} @endogenous x @parameters alpha @model x = alpha * x{-1}; \end{snippet} %} Or alternatively, using hash rather than backslashes :: m = rise.from_code_snippet('myModel'); %{ #begin{snippet}{myModel} @endogenous x @parameters alpha @model x = alpha * x{-1}; #end{snippet} %} Declaring a model as a Cell Array ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ You can also declare a model in RISE directly in MATLAB using a **cell array**. This approach allows you to write the model specification as a structured collection of strings representing different model components, such as variables, equations, and parameters. Example of declaring a model as a cell array:: simpleModel = { '%% model without parameters and shocks', '@endogenous x', '@model', 'x=1.05*x{-1};' }; m = rise(simpleModel); Handling Multiple Model Specifications -------------------------------------- This section outlines various methods to create models in RISE by defining endogenous variables, exogenous variables, parameters, and equations using different formats. Method 1: Simple Model File ~~~~~~~~~~~~~~~~~~~~~~~~~~~ To create a RISE model from a single model file:: m = rise('modelFile'); Or with an explicit extension:: m = rise('modelFile.rs'); Method 2: Multiple Model Files ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To create a RISE model from multiple model files:: m = rise({'modelFile1.rs', 'modelFile2.rs', ..., 'modelFilen.rs'}); You can also omit the extensions if the files are already known to have `.rs`, `.rz`, or `.dsge` extensions:: m = rise({'modelFile1', 'modelFile2', ..., 'modelFilen'}); Method 3: Declaring a Model with a Cell Array ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To declare a RISE model online using a cell array :: m = rise({ '@endogenous x y z', '@parameters alpha beta', '@model', 'x = alpha * y', 'y = beta * z' }) Method 4: Multiple Cell Arrays for Different Model Parts ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To declare multiple RISE model components using a cell array of cell arrays:: onlineCellstr1 = { '@endogenous e', '@exogenous x', '@model', 'x = e;' }; onlineCellstr2 = ... % Another set of model definitions onlineCellstr3 = { '@endogenous(log) C, I' }; m = rise({onlineCellstr1, onlineCellstr2, onlineCellstr3}); Method 5: Combination of Model Files and Cell Arrays ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ To create a RISE model by combining model files and cell arrays of model components:: info = struct(); info.disk_files = {'modelFile1.rs', 'modelFile2.rs', ..., 'modelFilen.rs'}; info.online_data = {'online_info1', ..., 'online_infoM'}; % You can also use cell arrays for online data info.online_data = {onlineCellstr1, onlineCellstr2, ...}; m = rise(info); This approach allows you to combine model components from both disk-based model files and online specifications written directly in MATLAB. Atoms declarations -------------------- Successive atoms can be separated by a blank spaces, a comma or both. Each variable and parameter name begins with a letter. RISE is case sensitive and supports Latin alphabet only. Digits and underscores are allowed in names provided they do not come first. .. _@endogenous: \@endogenous ~~~~~~~~~~~~~~~ **@endogenous** is the keyword for declaring the endogenous variables. Each variable name is optionally followed by its description in double quote marks. Example :: @endogenous C, I, R "Interest rate", PAI This block is compulsory!. The keyword **@endogenous(log)** can be used to declare variables for which a log-transform will be applied. Example :: @endogenous(log) C, I There can be multiple blocks of **@endogenous(log)**. **@endogenous(log_vars)** and **@endogenous(log_variables)** are accepted aliases. By default, a log variable is handled by an *inline* substitution: every occurrence of ``X`` in the equations is replaced by ``exp(X)``, so the variable that RISE solves for is internally the log and the level is recovered as ``exp(X)``. An alternative treatment is available through the parse-time option **explicit_log_levels** (default ``false``), set when the model is created:: m = rise('my_model','explicit_log_levels',true); When ``true``, for each log variable ``X`` RISE introduces an explicit linear log-state ``LOG_X``, replaces ``X`` with ``exp(LOG_X)`` in the structural equations, and adds a single static equation ``X = exp(LOG_X)``. The level ``X`` then exists as an explicit endogenous variable in its own right, while ``LOG_X`` is the variable the perturbation is taken in. .. note:: **explicit_log_levels** is currently supported for **stationary** models only. A balanced-growth solve (``solve_bgp=true``) is refused, because a level that grows multiplicatively (``X=exp(LOG_X)`` with ``LOG_X`` trending) cannot have a linear solution. Under this option no variable carries the internal log flag; ``X`` is a genuine level (so, for example, an observed ``X`` is treated as a level, not a log). .. deprecated:: 20260524 The legacy block-level forms **@log_variables**, **@log_vars** and **@level_variables** (with their **@all_but** complement) are still parsed for backwards compatibility but are deprecated. Use **@endogenous** for level variables and **@endogenous(log)** for log variables instead. The two styles cannot be mixed in the same model file. \@exogenous ~~~~~~~~~~~~~~~ **@exogenous** is the keyword for declaring the exogenous variables or shocks. Each variable name is optionally followed by its description in double quote marks. Example :: @exogenous EA, EZ "Technology shock", ER "Interest rate", EG This is only necessary if the model has some exogenous variables. \@parameters ~~~~~~~~~~~~~~~ **@parameters** is the keyword for listing the parameters. Each parameter name is optionally followed by its description in double quote marks. Example :: @parameters alpha, beta "discount factor", rho This is only necessary if there are parameters whose values can change In RISE, every parameter is controlled by a named Markov process. The name of the process controlling the constant parameters does not appear explicitly. That name cannot be changed, it is **const**. In the presence of a regime switching model, *@parameters* is followed by the name of a markov process and the number of states of the markov process and then the list of the parameters controlled by the markov process. Example :: @parameters(volatility,2) sige, siga "volatility of pref. shock", sigz In the RISE "religion", we use - "state" to denote the modes of a particular markov process. e.g. "volatility" in the code snippet above can be in state 1 or in state 2. - "regime" to denote a combination of states from different independent Markov processes. e.g. consider a model with two independent Markov processes : one controlling the behavior of policy (hawkish or dovish) and one controlling the heteroskedasticity of shocks (low volatility or high volatility). We can have - a regime of dovish stance of monetary policy and high volatility - a regime of hawkish stance of monetary policy and high volatility - a regime of dovish stance of monetary policy and low volatility - a regime of hawkish stance of monetary policy and low volatility Parameters for Transition probabilities """"""""""""""""""""""""""""""""""""""""" Markov processes give rise to transition probabilities. Transition probabilities have a specific syntax. The following rules have to be followed : - each transition probability starts with the name of the markov process it caracterizes. - each transition probability name must have exactly 3 underscores. - It is forbidden to declare diagonal elements of a transition matrix. - When transition probabilities are constant, they can be declared as parameters. - the general syntax is mcName_tp_i_j, {i,j}=1,2,..., where - mcName is the name of Markov process - tp stands for transition probability - i is the state today - j is the state tomorrow Parameters for Measurement Errors """"""""""""""""""""""""""""""""""""" Just like regular shocks, measurement errors are mean-zero and variance-one processes. However, by default, measurement errors are scaled by zero when not declared. The variability of measurement errors is changed by declaring parameters with a specific syntax. The syntax for declaring measurement error parameters and possibly their correlation is as follows - stderr_OBSNAME : scale on measurement error for observed endogenous variable OBSNAME - corr_OBSNAME1_OBSNAME2 : correlation of measurement errors on observed endogenous variables OBSNAME1 and OBSNAME2. .. warning:: for any observed variable :math:`X` declared as log variable, the measurement errored variable is :math:`X_{obs} = X\exp\left(stderr\_X\times E_{X}\right)` so that in log terms :math:`x_{obs} = x + stderr\_X\times E_{X}`. Parameters for Bounded Rationality """""""""""""""""""""""""""""""""""" RISE implements bounded rationality through the declaration of special parameters. See the section on tools for bounded rationality for details. The perturbation parameter `perturbator` """"""""""""""""""""""""""""""""""""""""" For any DSGE model, RISE always creates a parameter by default. The name of the parameter is `perturbator`. This parameter cannot be declared but may be used in the equations of your model. It has the property that in steady state it assumes a value of 0. Otherwise it assumes a value of 1. .. note:: - If the model has time-varying transition probabilities, RISE will automatically transform the equations defining those probabilities to satisfy the requirements of the Maih-Waggoner perturbation should it be used. - Likewise, if a model has constant/exogenous transition probabilities and that those transition probabilities are used in the equations of the model, RISE will apply the same scheme to all the occurrences of those exogenous transition probabilities. - However, the scheme will only matter if the Maih-Waggoner perturbation strategy is chosen as the perturbation strategy. \@observables ~~~~~~~~~~~~~~~ .. index:: filtering **@observables** is the keyword for declaring the variables to be observed during filtration. Only declared endogenous or exogenous variables can be observed. Example :: @observables PAI, R, Y Three remarks are in order : - Only observed endogenous variables can give rise to measurement error parameters - An exogenous variable that is observed is considered deterministic. For instance one can observed a time trend that affect some measurement equation. This gives us the flexibility to accommodate all kinds of exogenous observed variables. - time-varying probabilities end up being endogenous variables and so they can be observed. This block is optional. Necessary only if there is filtration. Log-approximated variables ~~~~~~~~~~~~~~~~~~~~~~~~~~ Use **@endogenous(log)** (see :ref:`@endogenous <\@endogenous>` above) to declare endogenous variables for which the approximation should be taken in logs. By default - i.e. when the variable is listed under a plain **@endogenous** block - the approximation is taken in levels. There are a few rules to be aware of when choosing log approximation: - log approximation cannot be applied to variables that are zero or negative at the steady state; - log approximation is optional for stationary variables with a positive steady state; - for nonstationary variables, log approximation is required when the growth rate is computed as :math:`X_{t}/X_{t-1}`. See also the computation-of-the-steady-state section for the consequences of this choice. .. deprecated:: 20260524 The legacy block forms **@log_variables**, **@log_vars** and **@level_variables** (optionally with **@all_but**) are still parsed for backwards compatibility but are deprecated. Prefer **@endogenous** + **@endogenous(log)**. The two styles cannot be mixed inside the same model file. On-the-fly atoms declarations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ We can also declare certain types of variables or parameters on the fly, i.e. directly in the model block. Each atom is followed by an appostrophe, followed by its type. - endogenous : X'e | X'e{t+1} | X'e{t-1} | X'e(t+1) | X'e(t-1) ... - exogenous : E'x | E'e{t+1} | E'e{t-1} | E'e(t+1) | E'e(t-1) ... - parameters : theta'p | theta'e{t+1} | theta'e{t-1} | theta'e(t+1) | theta'e(t-1) ... .. note:: If an atom is dated, the date comes after they type is declared. The \@functions block ---------------------- This block serves to define carry-around functions that appear in the other blocks such as \@model, \@steady_state_model \@optimization_problem, \@parameter_restrictions. Example :: @functions Uc(a,b,xc) = 1/sigma*xc - 1/sigma*a + k{t}; Uh(a,b,xh) = log(psi)-nu*xh+nu*b; The requirements are as follows: - The function should hold in one line and end with a semicolon. - The input arguments should be non-dated. - the right-hand side can have dates - preferably the function should not be called with arguments containing complicated comma structures. For instance in the expression below, if a=minus(plus(e,b),rdivide(c,d)) plus and rdivide will be correctly parsed but minus will not - The block can have comments but not equation tags The \@model block --------------------- The **@model** block is compulsory. This is where we declare the model equations. There are three types of equations that can enter the @model block. Regular equations ~~~~~~~~~~~~~~~~~~~ E.g. :: log(X{t}) = (1-rho)*log(xss) + rho*log(X{t-1}) + sig*E{t}; Equations broken across multiple lines ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ An Equation can be broken across multiple lines E.g. :: x{t} = rho1*x{t-1} + rho2*x{t-2} + rho3*x{t-3} + stde*e{t}; As in Matlab, one can add \"...\" to denote the breaking of lines E.g. :: x{t} = ... rho1*x{t-1} + ... rho2*x{t-2} + ... rho3*x{t-3} + ... stde*e{t}; As in Matlab, the \"...\" can be optionally followed by comments with no incidence on the subsequent computations. E.g. :: x{t} = ... rho1*x{t-1} + ... lag 1 rho2*x{t-2} + ... lag 2 rho3*x{t-3} + ... lag 3 stde*e{t}; The \@E operator for expectations ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Expectations are not always taken at time t. They can be taken earlier or after. The syntax is simple : @E[s](expression) or @E[t+s](expression) for expectations taken s period ahead (earlier if s is negative). Note that @E[0](expression) = expression, @E[s](y{t}) = y{t} if s>0. E.g. :: c{t}*theta*h{t}^(1+psi)=(@E[1]((1-alpha)*y{t})+@E[-2]((1-alpha)*y{t}))/2; Equations with auxiliary expressions :\"...$[]$...\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ E.g. :: exp(lb{t})=beta*exp(lb{t+1})*(alpha*exp($s{t+1}+y{t+1}$-k{t})+1-delta); RISE will treat the term $[]$ as a forward-looking term and create an auxiliary variable to it. The auxiliary variable will have prefix **DISCRDOLL**. In the example above, the equation above becomes :: exp(lb{t})=beta*exp(lb{t+1})*(alpha*exp(DISCRDOLL1{t+1}-k{t})+1-delta); And the definition of the auxiliary variable is DISCRDOLL1{t} = s{t} + y{t}; There is no requirement that all variables between $ signs be forward-looking. RISE will always lag the terms correctly when creating the corresponding auxiliary variable. .. hint:: **Relevance** : When solving discretionary or stochastic replanning problems, the derivatives of forward-looking terms enter the equations of the model. To reduced the costs of computation, to the extent that this is feasible, we can gather together several forward-looking variables instead of implicitly creating the derivatives of each one of them separately. Regular equations with equation simplification :\"...\#...\" ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ Regular structural equations can optionally be followed by a # sign and then a simplified version of the same equation to be used when computing he steady state or the balanced growth path. E.g. :: log(X{t}) = (1-rho)*log(xss) + rho*log(X{t-1}) + sig*E{t} # ... X{t}=xss; Definitions : \# Equation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RISE uses the pound sign at the beginning of an equation to declare a definition. This is an atom that is not declared elsewhere. Examples :: # beta = alpha + gamma; # OMG = Y{t}/X{t} + delta; The rules are as follows : - definitions can be functions of variables and parameters - if a definition is a function of variables, as is the case for the second definition above, then it has to be systematically substituded. - if a definition is a function of parameters only, it does not have to be substituted. - If one definition is a function of variables, all definitions have to be substituted - If definitions are functions of parameters, they have to be written in a recursive fashion such that one definition is either independent of the previous one or is a function of it. e.g :: # alpha = delta + omicron; # varrho = cos(alpha); - The substitution of definitions is done by setting the option *definitions_inserted* to true while "rising" the model :: m=rise(...,'definitions_inserted',true) Time-varying transition probabilities : \! Equation ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ When the transition probabilities are time varying, they can no longer be declared as parameters. They have to be declared in the model block. In order to differentiate them from other equations, we prefix them with an exclamation mark. E.g. :: ! volatility_tp_1_2 = 1/(1+exp(alpha*X{t})); ! pol_tp_1_2 = R>1; .. caution:: time-varying probabilities should always evaluate in [0,1]. .. hint:: time-varying probabilities end up being endogenous variables and so they can - be observed - have measurement errors, e.g. stderr_mpeff_tp_1_2, stderr_mpeff_tp_2_1 for some markov process mpeff with transition probabilities mpeff_tp_1_2 and mpeff_tp_2_1 - be dynamic and used in other equations Useful cumulative density functions that can be used for transition probablities """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" #. arc sine: :math:`u=\frac{2}{\pi }\sin ^{-1}\left( \sqrt{\frac{x-a}{b-a}}\right)` #. Exponential: :math:`u=1-\exp \left( -g\left( x-c\right) \right)` #. Gumbel: :math:`u=\exp \left( -\exp \left( -\frac{x-\mu }{b}\right) \right)` #. Inverse Gaussian: :math:`u=normcdf\left( \sqrt{\frac{\lambda }{x}}\left(\frac{x}{\mu }-1\right) \right) +\exp \left( \frac{2\lambda }{\mu }\right)normcdf\left( -\sqrt{\frac{\lambda }{x}}\left( \frac{x}{\mu }+1\right)\right)` #. Kumaraswamy: :math:`u=1-\left( 1-\left( \frac{x-c}{d-c}\right) ^{a}\right)^{b}` for :math:`x\in \left[ c,d\right]` #. Logistic: :math:`u=\frac{1}{1+\exp \left( -g\left( x-c\right) \right) }` for :math:`x\in \left( -\infty ,+\infty \right)` #. Log Normal : :math:`u=0.5\left[ 1+ \operatorname{erf}\left( \frac{\log \left( x\right) -a}{b\sqrt{2}}\right) \right]` for :math:`x\in \left( -\infty ,+\infty \right)` #. Normal: :math:`u=0.5\left[ 1+ \operatorname{erf}\left( \frac{x-a}{b\sqrt{2}}\right) \right]` for :math:`x\in \left( -\infty ,+\infty \right)` #. Pareto: :math:`u=1-\left( \frac{a}{x}\right) ^{b}` for :math:`x\in \left[ a,+\infty \right)` #. Raised cosine: :math:`u=0.5\left[ 1+\frac{x-\mu }{s}+\frac{1}{\pi }\sin\ \left( \frac{\left( x-\mu \right) }{s}\pi \right) \right]` for :math:`x\in \left[ \mu -s,\mu +s\right]` and :math:`s>0` #. Weibull: :math:`u=1-\exp \left( -\left( \frac{x}{b}\right) ^{a}\right)` for :math:`x\in \left[ 0,+\infty \right)` .. hint:: Note that those functions are monotonically increasing. One way to get them decreasing is to use the complement i.e. 1-u or 1-cdf(x,a,b) The **@optimization_problem** block ------------------------------------ The **@optimization_problem** block, formerly known as **@planner_objective**, is necessary only when solving optimal policy problems. It handles various types of policy, including: 1. **Commitment**: With or without regime switching. 2. **Discretion**: Linear-quadratic or nonlinear, with or without regime switching. 3. **Loose Commitment**: Switching between discretion and commitment with constant probability in a linear-quadratic framework. 4. **Stochastic Replanning**: Switching between discretion and commitment with possibly time-varying probabilities in a nonlinear framework. In these cases, the number of equations should be strictly less than the number of endogenous variables. .. hint:: By default, the “solver” option is always empty if not set - RISE will check whether the system can be solved by eigenvalue methods. If this is the case, the option will be set to the default RISE solver for constant-parameter models : `rise_1` - else RISE will use the default solver for regime-switching models : `mfi` - Given the way RISE is organized, discretionary policy can be solved using `rise_1`. This is because the problem can be solved conditional on the knowledge of the solution of the forward-looking variables. In this way, one can in principle, study the indeterminacy properties of a discretionary model. - But we believe that insisting that the solution should be determinate is a waste of time. One thing is to say that for a particular parameterization we have a unique solution. Yet another thing is to say that for a solution to be interesting or useful, it has to be determinate. There is no justification for such a stance other than the fact that people sometimes say : “If I have many solutions I don’t know which one to choose.” Note that the only people who would make such complains are the ones solving linear or linearized DSGE models. - With that said, the user is nowfree to choose which solver hewants to use. But I am just stressing that the behavior of `rise_1`, which insists on determinacy is different from that of `mfi`, which applies functional iteration to find a good solution. Both of those solvers are different from the Newton solvers `mn` and `mnk`, which are locally stable around an equilibrium and try to find the solution that is the closest to the starting point. Other solvers are `dsge_groebner`, which tries to find all possible solutions. - Should you want to solve for all possible solutions, there are also `dsge_schur` and `dsge_udc` that can do the job but they are not appropriate for this context as they can be computationally taxing. Generic Syntax ~~~~~~~~~~~~~~~~ The generic syntax for defining an optimal policy in RISE is :: @optimization_problem[options]{core problem settings} **Options**: - `@no_u_turn = true/false` : If `true`, only Ramsey/commitment policies will be computed, and discretion will not be considered. Default is `false`. - `@commitment = 1/0` : `1` for Ramsey/commitment, `0` for discretion. Default is `@commitment = 1`. - `@markov_process = nameOfMarkovProcess` : Specifies the Markov process controlling the game. The default is `"const"`, meaning there are no switches in the game. **Core Problem Settings**: - `@objective = objective function` : The objective function of the policymaker, e.g., `log(C{t})`. - `@order = integer` : The hierarchy among players in the presence of multiple policymakers. This is optional and defaults to `1`. - `@instrument = variableName` : The policy instrument, optional for a single player and mandatory with multiple players. - `@discount = beta` : The player's discount factor, optional and defaults to `0.99`. - `@alias = aliasName` : A shorthand name for the policymaker. This option is discontinued! - `@constraint = constraint(s)` : Constraints to the optimization problem, e.g., `R>=1`. - This basic syntax applies particularly for perfect foresight (or potentially other solution techniques). - Multiple constraints are separated by `&`, e.g., `R>=1 & K<2`. - Inequalities are strictly enforced only under perfect foresight. - In a stochastic environment, it maybe useful to transform the problem into a regime-switching one. This is done by adding a regime indicator in front of the constraint as "regime_indicator_m:Inequality_constraints_m". e.g. `gam:R>=1 & delta:K<2`. In this case, - The regime indicators components are switching parameters such that when they assume value 1, the inequality restrictions (constraint) become binding. Conversely, when they are 0, the constraints do not bind. - Internally, a Lagrange multiplier will be associated with the constraints such that a constraint `gam:R>=1` written as `Lambda.(R-1)=0` becomes `(1-gam).Lambda+gam.(R-1)=0`. .. caution:: Each constraint must be an inequality "<", ">", "<=" or "<=" .. attention:: Strict inequalities will be treated as loose inequalities. .. error:: The inequalities cannot be represented by functions such as "le", "lt", "gt", "ge". .. error:: It is not possible to combine inequalities with regime indicators and inequalities without regime indicators. Either you do perfect foresight or you do regime switching. .. tip:: It is possible to define a regime indicator as an endogenous variable instead of a parameter and still use it in a constraint for the purpose of doing perfect foresight. .. tip:: In the solving of the steady state, in the absence of an analytical solution it often helps to have a steady state version of the euler equation that gives the solution of the interest rate both in normal times and in abnormal times :: RHO = 40/41*RHO(+1)+1/41*(I-PAI(+1)) # (1-gam)*(I-0) + gam*(I-elb) = 0 ; Optimal Policy with No U-Turn ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ RISE provides the option to switch seamlessly between discretion and commitment, but this flexibility comes at a computational cost. If you intend to solve only for Ramsey/Commitment policies, it is advisable to set the `@no_u_turn` option to `true`: :: @optimization_problem[@no_u_turn=true, ...]{ @objective = pi_c^2 + y^2, ... } Setting `@no_u_turn` to `true` disables the standard algorithms for solving discretionary or stochastic replanning problems, limiting the solver to loose commitment approaches. .. hint:: If `@no_u_turn` is set to `true`, - the only appropriate solver is `"loose_commitment"`, which works well in linear-quadratic setups but results in lower accuracy for nonlinear problems. - Higher-order perturbation methods cannot be applied under this setting. Ramsey Policy ~~~~~~~~~~~~~~~~~ To solve for a Ramsey (commitment) policy, the syntax is:: @optimization_problem[@no_u_turn=false, @commitment=1]{ @objective = pi_c^2 + y^2, @discount = beta } or, preferably:: @optimization_problem[@no_u_turn=false]{ @objective = pi_c^2 + y^2, @discount = beta } Then set the model to solve for Ramsey policy:: m = set(m, 'solve_policy_type', 'ramsey'); The following obsolete syntax is still supported but should be avoided:: @optimization_problem {discount=beta} pi_c^2 + y^2; Discretionary Policy ~~~~~~~~~~~~~~~~~~~~~~~ To solve for a discretionary policy, the syntax is:: @optimization_problem[@no_u_turn=false, @commitment=0]{ @objective = pi_c^2 + y^2, @discount = beta } or, preferably:: @optimization_problem[@no_u_turn=false]{ @objective = pi_c^2 + y^2, @discount = beta } Then set the model to solve for discretionary policy:: m = set(m, 'solve_policy_type', 'discretion'); .. hint:: By default, RISE will check whether the system can be solved by eigenvalue methods, and if possible, use the default solver `rise_1`. Otherwise, it will use the `mfi` solver for regime-switching models. Loose Commitment ~~~~~~~~~~~~~~~~~~ Loose commitment is defined as switching between commitment and discretion with a constant probability in a linear-quadratic system. :: @optimization_problem[@no_u_turn=true]{ @objective = pi_c^2 + y^2, @discount = beta } @parameters(looseCommit, 2) commitment @parameters looseCommit_tp_1_2, looseCommit_tp_2_1 Alternatively, the probabilities can be declared as endogenous:: @endogenous looseCommit_tp_1_2, looseCommit_tp_2_1 With the following restriction:: looseCommit_tp_1_2 = 1 - looseCommit_tp_2_1; .. note:: The name of the Markov process `"looseCommit"` is arbitrary, but: - The number of states must be exactly 2. - The `"commitment"` indicator takes values 1 (commitment) or 0 (discretion). - It is up to the user to choose the state in which commitment=1 and the state in which commitment = 0 .. hint:: For estimation, one way to enforce the restriction `looseCommit_tp_1_2 = 1 - looseCommit_tp_2_1` is - to declare an auxiliary parameter, say probCom, as non-switching - set both looseCommit_tp_1_2 and looseCommit_tp_2_1 as endogenous probabilities i.e.:: ! looseCommit_tp_1_2 = probCom; ! looseCommit_tp_2_1 = 1 - probCom; - estimate probCom Stochastic Replanning ~~~~~~~~~~~~~~~~~~~~~~ In stochastic replanning, the system switches between discretion and commitment with potentially time-varying probabilities. :: @optimization_problem[@no_u_turn=false]{ @objective = pi_c^2 + y^2, @discount = beta } @parameters(stochrepl, 2) commitment The transition probabilities `stochrepl_tp_1_2` and `stochrepl_tp_2_1` can be either endogenous or exogenous. .. note:: The Markov process `"stochrepl"` is arbitrary, but the number of states must be exactly 2. Multiple Policymakers : Non-cooperative games ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ For multiple policymakers, each player is declared with the following format, where the name of the policymaker is followed by a colon: Example:: @optimization_problem{ Monetary_policy: @order = 1, @discount = beta1, @objective = objective1, @instrument = R; Fiscal_policy: @order = 3, @discount = beta2, @objective = objective2, @instrument = TAX; Macroprudential_policy: @order = 2, @discount = beta3, @objective = objective3, @instrument = Y } .. note:: - Under `Nash bargaining` all players move simultaneously - Under `Stackelberg bargaining` there are leaders and followers - `@order` here refers to the hierarchy with 1 > 2 > 3,... etc. - Several players can move at the same time .. hint:: For non-cooperative games you can additionally choose between two equilibrium concepts at solve time: *open-loop equilibrium* (OLE, the historical default, each player takes the opponent's path as given) and *Markov-perfect equilibrium* (MPE, each player takes the opponent's policy function as given). Toggle with:: m = solve(m, 'solve_policy_equilibrium', 'OLE'); % default m = solve(m, 'solve_policy_equilibrium', 'MPE'); See :doc:`../OptimalPolicy/Optimal Policy` for the conceptual difference and the small restrictions (stochastic replanning rejects the option; ``@no_u_turn = true`` makes the MPE addition a no-op). Switching Games ~~~~~~~~~~~~~~~~~ RISE also allows the solving of problems in which the game to be played can change from one period to another (e.g., independent monetary and fiscal policy in some states, cooperative in others). When there is a switch in the type of game being played, several steps must be followed: 1. Declare the Markov process controlling the switching process as option `@markov_process`, e.g., `@markov_process=buscycl`. 2. Specify the corresponding transition probabilities either as parameters or as endogenous variables if time-varying. 3. Use `@state(istate){sub-core problem}` to define the core problem for each state. Example:: @optimization_problem[@no_u_turn=true, @markov_process=buscycl]{ @state(1){ @objective = omega_welf1*UTIL1{t} + omega_welf2*UTIL2{t}, @discount = betap } @state(2){ monetary_authority: @objective = UTIL1{t}, @discount = betap, @order = 1, @instrument = INFL; financial_regulator: @objective = UTIL2{t}, @discount = betap, @order = 2, @instrument = BT } } In this example, two states are defined but the number can be arbitrary. In state 1, a single welfare function is optimized, while in state 2, two separate policymakers (monetary authority and financial regulator) optimize their objectives with the monetary authority as leader and the financial regulator as follower. The \@steady_state_model block (optional) ------------------------------------------ RISE gives you the flexibility of setting the program for solving the steady state or the balanced-growth path of the model either in the model file or outside the model file. The former strategy, presented below, is appealing when the user does not want to create too many files and that the model is small. The latter strategy gives the most flexibility including the possibility of overriding the information set inside the model file. The **@steady_state_model** block should compute the steady state (and the balanced-growth path) analytically.In the absence of this block, all variables are assumed to be zero in steady state. Of course, RISE will check whether this is true and try to improve on this if indeed the zero assumption does not hold. The program will calculate both the variables and the parameters whose values are set in steady state. It is important that the calculation be done in a recursive fashion. If the model is stationary, a single value is required for each variable. If the model is nonstationary, each variable should be a 1 x 2 vector in which the first element is the steady state and the second element is the growth rate. You can also loop around the steady state model conditional on the knowledge of variables not calculated in steady state. This arises typically in optimal policy problems, where for instance the value of, say inflation is not known but the system is such that if we knew the value of inflation we could solve for many other endogenous variables. .. warning:: In the steady state model, avoid using temporary variable that correspond to the names of endogenous variables! .. hint:: For level nonstationary variables, the growth rate is computed as :math:`X_{t}-X_{t-1}` whereas for log nonstationary variables, the growth rate is computes as :math:`X_{t}/X_{t-1}` .. hint:: The steady state for nonstationary variables is undefined but can be normalized. Suppose, say, we have the following system .. math:: h_{t}=\frac{1}{3} Y_{t}=Z_{t}h_{t} \log \left( \frac{Z_{t}}{Z_{t-1}}\right) = \log \left(\mu_{z}\right) +\sigma _{z}\varepsilon _{z,t} where :math:`\varepsilon _{z,t}`, :math:`Y_{t}` is output, :math:`Z_{t}` is the TFP and :math:`h_{t}` is the labor input. Assuming we do not take a log approximation of :math:`h_{t}`, the RISE steady state is given by .. math:: h = \left[\frac{1}{3},0\right] Z = \left[zss,\mu_{z}\right] Y = \left[Z\left(1\right)\times h\left(1\right),Z\left(2\right)\right] where zss is the normalization for the steady state of Z or more precisely the point around which the approximation will be taken. .. hint:: Sometimes, part of the steady state cannot be computed analytically. You can write a separate function in an m-file that solves the sub-problem using a root-finding procedure. That function can then be called from within the *@steady_state_model* block. .. warning:: If you write a separate function that solves part of the steady state and that can fail at times for some parameterizations of the model, there is no way to inform RISE of the failure when using a *@steady_state_model* block. The most flexible way to deal with this is to use a steady-state file. The alternative to the @steady_state_model block is the steady state file. The \@transition_functions block (optional) --------------------------------------------- The **@transition_functions** block is where *time-varying transition probabilities* (TVTPs) are declared. A TVTP is a transition probability that depends on model variables (and/or parameters), so that the probability of moving between regimes changes over time — for example an endogenous-switching zero-lower-bound or a regime that becomes more likely as a variable approaches a threshold. Each entry has the form :: chain_tp_i_j = expression ; where ``chain`` is the name of a declared Markov chain and ``i``, ``j`` index the transition from state ``i`` to state ``j``. An optional description in double quotes may precede the entry. Example :: @transition_functions "probability of leaving the low-rate regime" zlb_tp_1_2 = 1 - 1/(1+exp(-0.1*(R-1))); zlb_tp_2_1 = 0.3 ; The Markov chain must be declared, which is done by attaching a switching parameter to it, e.g. ``@parameters(zlb, 2) some_param``. The right-hand side may reference contemporaneous endogenous variables, exogenous variables, parameters, and #-definitions; it must **not** contain leads or lags. In optimal-policy models the right-hand side may also reference a constraint multiplier through ``@multiplier(n)`` (state-dependent switching driven by how binding a constraint is). **Multiple @transition_functions blocks** are allowed in the same file and are stitched together by the parser; you can put a chain's two probabilities in two separate blocks, or interleave them with other declarations, with no change in behaviour. **Solver note.** When the right-hand side depends on an endogenous variable, the default functional-iteration solver (``'mfi'``) can fail to converge. Use the Newton-iteration solver explicitly: ``solve(m,'solver','mn')``. For a stable solution keep the transition probabilities strictly inside ``(0,1)`` — a common trick is ``p_ij = p_min + (p_max - p_min)*f(state)`` with ``p_min``, ``p_max`` in ``(0,1)``. .. note:: Transition-probability names (``chain_tp_i_j``) must be declared **here**, not in **@endogenous** — listing them as endogenous variables is an error. The legacy syntax of writing ``!chain_tp_i_j = ...`` inside the **@model** block is still parsed but deprecated; prefer **@transition_functions**. A *constant* transition probability does not need this block: it can simply be a plain parameter. The \@epilogue block (optional) --------------------------------- The **@epilogue** block declares *post-solve derived series* — quantities that are not part of the structural model but are computed from the model variables **after** the model has been solved and simulated (for example annualised inflation, great-ratios, or other transformations you want returned alongside the model's output). Each entry is an assignment :: @epilogue annual_inflation = 4*PAI ; real_rate = (1+R) / (1+annual_inflation/4) - 1 ; Unlike the **@model** block, leads and lags inside **@epilogue** are interpreted as *literal time shifts* on the simulated path, not as expectations: ``annual_inflation{-1}`` resolves to ``lag(annual_inflation, 1)``, ``annual_inflation{+2}`` to ``lead(annual_inflation, 2)``. The right-hand side may reference endogenous, exogenous, parameter, and ``#``-definition names, as well as **earlier @epilogue entries**: RISE topologically sorts the entries before compilation so the order of declaration matters only up to dependency, and **mutual** or **self-references** are rejected with a clear error. Multiple ``@epilogue`` blocks are stitched together in the same way as ``@transition_functions``. Epilogue variables never enter the structural solution. Transition-probability (``chain_tp_i_j``) names are not allowed here — declare those in **@transition_functions**. The runtime evaluator is invoked automatically on the simulation, IRF, forecast, filter, perfect-foresight, counterfactual, and brute-force-simulate outputs, so an ``@epilogue`` series appears as a regular field on the returned ``ts`` struct alongside the model variables. The \@parameterization block (optional) ------------------------------------------ RISE gives you the flexibility of setting the parameterization of the model either in the model file or outside the model file. The former strategy, presented below, is appealing when the user does not want to create too many files and that the model is small. The latter strategy gives the most flexibility including the possibility of overriding the information set inside the model file. Inside the model file, the parameterization is set under the "@parameterization" block. This concerns both the parameters that are fixed and the parameters that are to be estimated. A parameter cannot be repeated and the start value for estimation will also serve as the baseline calibration, should the parameter not be estimated later on. For fixed parameters, the syntax is :: paramName, value ; paramName = value ; For estimated parameters, the syntax is :: paramName, start_value, arg1, arg2,...,argn ; paramName = start_value, arg1, arg2,...,argn ; where arg1, arg2,...,argn refers to additional arguments. See the section on priors for detail. Example :: rho, 0.75, 0.4, 0.9, beta(0.9); rho = 0.75, 0.4, 0.9, beta(0.9); Switching parameters are written as :: sigz(vol,1) sigz(vol,2) or as :: sigz_vol_1 sigz_vol_2 The \@parameter_restrictions block (optional) -------------------------------------------------- The **@parameter_restrictions** block sets the restrictions to be enforced during estimation The syntax is :: @parameter_restrictions f1(theta)>=f2(theta); ... h1(theta)<=h2(theta); This can also be set outside the model file. See e.g. the chapter on estimation. Tools for bounded rationality (Non-rational expectations) ---------------------------------------------------------- Hybrid Expectations ~~~~~~~~~~~~~~~~~~~~~~ The key equations in a hybrid expectations system are the following (see e.g. :cite:`GelainEtAl2013`): .. math:: F_{t}X_{t+1} = F_{t-1}X_{t} + \lambda\left(X_t-F_{t-1}X_t\right) E_t^{he}X_{t+1} = \omega F_t X_{t+1} + \left(1-\omega\right)E_t X_{t+1} where :math:`0<\lambda\le 1` and :math:`0\le\omega\le 1`. RISE implements **Hybrid expectations** through the declaration of the following two parameters : - hbe_w : weight on adaptive (or backward-looking ) expectations - hbe_lambda : weight on current relative to past in backward-looking expectations Cognitive discounting ~~~~~~~~~~~~~~~~~~~~~~~ RISE implements cognitive discounting a-la Gabaix in two distinct ways: #. Through the creation of parameter names of the form "mcd_VARIABLENAME" where VARIABLENAME is the name of an endogenous variable present in the model #. Through the declaration of list of endogenous variables to which one wants to apply cognitive discounting. e.g. @cognitive_discount VARIABLE1, VARIABLE2,... In this case, RISE will create the corresponding cognitive discounting parameters "mcd_VARIABLE1", "mcd_VARIABLE2", ... This way of setting cognitive discounting can be applied to nonlinear and regime-switching models and in that case, the degree of discounting can change from one regime to another. One way to apply regime switching to cognitive discounting parameters is just to add them to the list of parameters controlled by a particular markov process. But another way to do the same using the second approach above is just to add the markov process to the declaration block. e.g :: @cognitive_discount(MCCHAIN,nstates) VARIABLE1, VARIABLE2,... Macro Language for preparsing -------------------------------- .. - \@log_variables - \@level_variables - \@all_but Inclusion of files ~~~~~~~~~~~~~~~~~~ .. code-block:: matlab @include(filename) @include "filename" @import(filename) @import "filename" Pseudo functions ~~~~~~~~~~~~~~~~~~ .. include:: pseudo_functions.rst Control flow : for loops ~~~~~~~~~~~~~~~~~~~~~~~~~ :: @for c=[1,4,6] Y_@{c}=rho_@{c}*Y_@{c}{-1}+sig_@{c}*E_@{c}; @end will produce Y_1=rho_1*Y_1{-1}+sig_1*E_1; Y_4=rho_4*Y_4{-1}+sig_4*E_4; Y_6=rho_6*Y_6{-1}+sig_6*E_6; :: @for c=1:3 Y_@{c}=rho_@{c}*Y_@{c}{-1}+sig_@{c}*E_@{c}; @end will produce Y_1=rho_1*Y_1{-1}+sig_1*E_1; Y_2=rho_2*Y_2{-1}+sig_2*E_2; Y_3=rho_3*Y_3{-1}+sig_3*E_3; :: @for c={'','_f'} Y@{c}=rho@{c}*Y@{c}{-1}+sig@{c}*E@{c}; @end will produce Y=rho*Y{-1}+sig*E; Y_f=rho_f*Y_f{-1}+sig_f*E_f; :: @for c={'ca','fr','de','be'} Y_@{c}=rho_@{c}*Y_@{c}{-1}+sig_@{c}*E_@{c}; @end will produce Y_ca=rho_ca*Y_ca{-1}+sig_ca*E_ca; Y_fr=rho_fr*Y_fr{-1}+sig_fr*E_fr; Y_de=rho_de*Y_de{-1}+sig_de*E_de; Y_be=rho_be*Y_be{-1}+sig_be*E_be; control flows : zipped for loops ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @for (aa,bb)=zip({'S','I','R'},{'Susceptible','Infected','Recovered'}) BIG_U@{aa} "welfare @{bb}", C@{aa} "consumption (@{bb})" @end will produce BIG_US "welfare Susceptible", CS "consumption (Susceptible)" BIG_UI "welfare Infected", CI "consumption (Infected)" BIG_UR "welfare Recovered", CR "consumption (Recovered)" control flows : enumerated for loops ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @for (aa,bb)=enumerate({'Susceptible','Infected','Recovered'}) BIG_U@{aa} "welfare @{bb}", C@{aa} "consumption (@{bb})" @end will produce BIG_U1 "welfare Susceptible", C1 "consumption (Susceptible)" BIG_U2 "welfare Infected", C2 "consumption (Infected)" BIG_U3 "welfare Recovered", C3 "consumption (Recovered)" Evaluations ~~~~~~~~~~~~~ @{term to be evaluated} where the term to be evaluated is not an index :: @for c=[1,4,6,8] Y_@{c}=rho_@{3*@{c}+1}*Y_@{c}{@{-1+3}}+sig_@{c}*E_@{c}; @end will produce Y_1=rho_4*Y_1{2}+sig_1*E_1; Y_4=rho_13*Y_4{2}+sig_4*E_4; Y_6=rho_19*Y_6{2}+sig_6*E_6; Y_8=rho_25*Y_8{2}+sig_8*E_8; Control flow : \@if ... \@elseif ... \@else ... \@end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @if strcmp(Policy,'Taylor rule') R{t}=rho*R{t-1}+(1-rho)*[psi_pai*PAI+psi_y*Y]+sigr*ER; @if strcmp(Policy,'Money growth rule') DM{t}=rhom*DM{t-1}+(1-rhom)*[-delta_pai*PAI-delta_y*Y]+sigm*EM; @else omgr*R{t}+omgm*DM{t}=omgr1*R{t-1}+omgm1*DM{t-1}+omg_pai*PAI+omg_y*Y+sigrm*ERM; @end Control flow : \@switch ...\@case ... \@otherwise ... \@end ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ :: @switch Policy @case 'Taylor rule' R{t}=rho*R{t-1}+(1-rho)*[psi_pai*PAI+psi_y*Y]+sigr*ER; @case 'Money growth rule' DM{t}=rhom*DM{t-1}+(1-rhom)*[-delta_pai*PAI-delta_y*Y]+sigm*EM; @otherwise omgr*R{t}+omgm*DM{t}=omgr1*R{t-1}+omgm1*DM{t-1}+omg_pai*PAI+omg_y*Y+sigrm*ERM; @end lower and upper cases ~~~~~~~~~~~~~~~~~~~~~~~ :: @for cc = {'cmr','rca','cng'} YSTAR_CEMAC_@{cc} =' @for cc2 = {'CMR','RCA','CNG'} @if ~strcmp('@{cc2}','@{cc}') + w_@:{cc}_@.{cc2}_5*YGAP_@{cc2} @end @end ; @end will produce YSTAR_CEMAC_cmr = + w_CMR_cmr_5*YGAP_CMR + w_CMR_rca_5*YGAP_RCA + w_CMR_cng_5*YGAP_CNG ; YSTAR_CEMAC_rca = + w_RCA_cmr_5*YGAP_CMR + w_RCA_rca_5*YGAP_RCA + w_RCA_cng_5*YGAP_CNG ; YSTAR_CEMAC_cng = + w_CNG_cmr_5*YGAP_CMR + w_CNG_rca_5*YGAP_RCA + w_CNG_cng_5*YGAP_CNG ;